//
//  main.cpp
//  raytrace
//
//  Created by M on 9/9/12.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include <vector>
#include "SceneHandler.h"
#include "Ray.h"
#include "Sphere.h"
#include "Light.h"
#include "../glm/glm.hpp"


#ifdef __APPLE__
//#include <glew.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif


SceneHandler *scene;

GLuint image;


int width = 480;
int height = 480;

int c = width * height;

std::vector<Sphere*> objects; 
std::vector<Light*> lights; 

vec4 finalColor[480 * 480];


using namespace glm;


// make so that the function returns a bool and t is a pointer, so we can find the intersection point
float raySphere(Ray *r, Sphere *sphere)
{
    vec3 v = sphere->getPos() - r->getPos();
    float B = 2.0 * dot(r->getRay(), v);
    float C = dot(v, v) - sphere->getRadius();
    
    float D = D * D - 4.0 * C;

    if(D < 0.0)
        return INFINITY;
    
    float t0 = (-B - sqrtf(D)) / 2.0;
    float t1 = (-B + sqrtf(D)) / 2.0;
    
    if(t0 > 0.0)
        return t0;
        
    if(t1 > 0.0)
        return t1;
    
    return INFINITY;
}   



void sceneCreation()
{

    Sphere *sphere1 = new Sphere(vec3(width/2, height/2, -10), 50000);
    sphere1->getMaterial()->setMaterialProperties(vec4(0, 0, 1, 1), 0, 0);
    objects.push_back(sphere1);
    
    Sphere *sphere2 = new Sphere(vec3(width/4, height/4, -10), 10000);
    sphere2->getMaterial()->setMaterialProperties(vec4(1, 0, 0, 1), 0, 0);
    //objects.push_back(sphere2);
    
    Light *light1 = new Light(vec3(0,0, 0), vec3(0, 0, -10000), vec4(1, 0, 0, 1));
    lights.push_back(light1);
    
}

void raytracing()
{
    float intersect;
    Ray *r;
    float lambertShade;
    
    // send a ray out for each pixel of the screen and check for intersections
    for (int  x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            
             r = new Ray(vec3(x, y, 0), vec3(x, y, -100));
            
            
            for (int i = 0; i < objects.size(); i++) {
                
                intersect = raySphere(r, objects[i]);
                
                if (intersect != INFINITY) {
                    
                        vec3 intersectionPoint = r->getPos() + intersect*r->getRay();
                        vec3 sphereNormal = normalize((intersectionPoint - objects[i]->getPos()) / objects[i]->getRadius());
                     
                        vec3 l = normalize(lights[0]->getPos() - intersectionPoint);
                        lambertShade = dot(sphereNormal, l); 
                        //lambertShade = abs(lambertShade);
                        std::cout<<lambertShade<<std::endl;
                    
                        finalColor[(y * width) + x] = objects[i]->getMaterial()->getColor() * lambertShade * 0.9 + objects[i]->getMaterial()->getColor() * 0.1;
                        //finalColor[(y * width) + x] = objects[i]->getMaterial()->getColor();
                
                }
                
                else
                {
                    
                    //finalColor[(y * width) + x] = vec4(1, 1, 1, 1);
                    
                }
                
            }
            
            /*if (intersect != INFINITY) {
             for (int i = 0; i < lights.size(); i++) {
             }
             }*/
            
        }
    }

    
   /* for (int i = 0; i < c; i++) {
        finalColor[i] = vec4(1, 0.5, 0, 1);
    }*/
}

void texture()
{

    glEnable(GL_TEXTURE_2D); // Enable texturing
	
	glGenTextures(1, &image); // Generate a unique texture ID
	glBindTexture(GL_TEXTURE_2D, image); // Activate the texture
    
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, width, height, 0, GL_RGBA, GL_FLOAT, finalColor);
	    
	glBindTexture(GL_TEXTURE_2D, 0);
    
}

void init()
{
 
    scene = new SceneHandler();
    
    sceneCreation();
    raytracing();
    texture();

}


void draw()
{
    scene->setupViewPort(width, height); 

    glBindTexture(GL_TEXTURE_2D, image);
    scene->drawQuad();
    glBindTexture(GL_TEXTURE_2D, 0);

    glutSwapBuffers();

    
}


int main (int argc, char * argv[])
{

    scene->setupWindow(100, 100, width, height, argc, argv, (char*)"ray trace");


    init();

    glutDisplayFunc(draw);
	glutIdleFunc (draw);
	glutMainLoop();


}

